package edu.wpi.cs509.clientlogic;

import edu.wpi.cs509.common.exceptions.IllegalMove;
import edu.wpi.cs509.common.exceptions.InitialPlacementError;
import edu.wpi.cs509.common.exceptions.InvalidLocation;
import edu.wpi.cs509.common.exceptions.PieceNotFound;
import edu.wpi.cs509.common.exceptions.ServerUnreachable;
import edu.wpi.cs509.messages.server.MsgMovePiece;
import edu.wpi.cs509.messages.server.MsgPlayerReady;
import edu.wpi.cs509.messages.server.MsgQuitGame;
import edu.wpi.cs509.representation.ActionAdd;
import edu.wpi.cs509.representation.ActionMove;
import edu.wpi.cs509.representation.ActionRemove;
import edu.wpi.cs509.representation.ActionNotLegalException;
import edu.wpi.cs509.representation.ClientGame;
import edu.wpi.cs509.representation.GameID;
import edu.wpi.cs509.representation.Gameboard;
import edu.wpi.cs509.representation.Location;
import edu.wpi.cs509.representation.PlayerPiece;
import edu.wpi.cs509.representation.TeamColor;
import edu.wpi.cs509.ui.intfc.GameEventNotify;
import edu.wpi.cs509.ui.intfc.GameInterface;

public class GameInterfaceObject implements GameInterface {


	
	//Constructor
	public GameInterfaceObject(ClientGame game) {
		ClientLogic.getInstance().setGame(game);
	}
	
	public ClientGame getGame() {
		return ClientLogic.getInstance().getGame();
	}
	
	@Override
	public void placePiece(Location loc, PlayerPiece piece) throws IllegalMove,
			InvalidLocation, ServerUnreachable {
		PlayerPiece currentPieceInLoc;
		ActionAdd addPiece;
		GameEventNotify gameHandle = ClientLogic.getInstance().getGameEventHandle();
		if (gameHandle == null) {
			System.out.println("ERROR: GameEventNotify handle is null...this should not happen - Debug this");
			return;
		}
		
		if (getOpponentColor().equals(piece.getColor())) {
			throw new IllegalMove("Trying to place opponents piece.");
		}
		
		currentPieceInLoc = getGame().getGameboard().getPlayerPieceFromLocation(loc);
		if (currentPieceInLoc != null) {
			throw new InvalidLocation("Piece already in chosen location.");
		}
		addPiece = new ActionAdd("Initial Piece Move", getGame().getGameboard(), piece, loc);
		try {
			addPiece.strategoRulesCheck();
		} catch (ActionNotLegalException e){
			throw new IllegalMove("Move is not legal.");
		}
		try {
			System.out.println("Sending a piece placement.");
			ClientDownstreamLogic.getInstance().sendDownstream(new MsgMovePiece(getGame().getGameID(), addPiece));
		} catch (Exception e) {
			throw new ServerUnreachable("Could not connect to Server.");
		}
	}

	@Override
	public void ready() throws InitialPlacementError {
		PlayerPiece playerPiece;
		for (int index = 0; index < Gameboard.PIECES; index++) {
			playerPiece = getGame().getGameboard().getPlayerPiece(getMyColor(), index);
			if (playerPiece.getLocation().isInBoneyard()) {
					throw new InitialPlacementError("Not all pieces are placed.");
			}
		}
		try {
			ClientDownstreamLogic.getInstance().sendDownstream(new MsgPlayerReady(getGame().getGameID()));
		} catch (ServerUnreachable e) {
			throw new InitialPlacementError("Unable to tell server you are ready, disconnected.");
		}
	}

	/**
	 * Move a piece from a location to a new location.
	 * 
	 * @param from - Current piece location
	 * @param to - Where the piece is moving to
	 */
	public void move(Location from, Location to)
			throws IllegalMove, ServerUnreachable {
		PlayerPiece currentPieceInFromLoc;
		PlayerPiece currentPieceInToLoc;
		ActionMove movePiece;
		GameEventNotify gameHandle = ClientLogic.getInstance().getGameEventHandle();
		if (gameHandle == null) {
			System.out.println("ERROR: GameEventNotify handle is null...this should not happen - Debug this");
			return;
		}
		
		/* Ensure the piece we are trying to move is our piece */
		currentPieceInFromLoc = getGame().getGameboard().getPlayerPieceFromLocation(from);
		if (currentPieceInFromLoc == null) {
			throw new IllegalMove("No piece is in this location.");
		} else if (currentPieceInFromLoc.getColor() != getMyColor()) {
			throw new IllegalMove("Trying to move an opponents piece.");
		}
		
		/* Ensure that we are moving to an empty place, or a spot occupied by an opponent */
		currentPieceInToLoc = getGame().getGameboard().getPlayerPieceFromLocation(to);
		if (currentPieceInToLoc != null) {
			if (currentPieceInFromLoc.equals(currentPieceInToLoc)) {
				throw new IllegalMove("Trying to move piece to the same location.");
			} else if (currentPieceInToLoc.getColor() == currentPieceInFromLoc.getColor()) {
				throw new IllegalMove("Trying to move piece to a location where you currently have a piece.");
			}
		}
		
		movePiece = new ActionMove("In Game Move", getGame().getGameboard(), currentPieceInFromLoc, to);
		try {
			movePiece.strategoRulesCheck();
		} catch (ActionNotLegalException e){
			throw new IllegalMove("Move is not legal.");
		}
		try {
			ClientDownstreamLogic.getInstance().sendDownstream(new MsgMovePiece(getGame().getGameID(), movePiece));
		} catch (Exception e) {
			throw new ServerUnreachable("Could not connect to Server.");
		}
	}

	/**
	 * Quit a game
	 * @throws ServerUnreachable 
	 */
	public void quit() throws ServerUnreachable {
		try {
                    ClientDownstreamLogic.getInstance().sendDownstream(new MsgQuitGame(getGame().getGameID()));
		} catch (Exception e) {
			throw new ServerUnreachable("Could not connect to Server.");
		}
	}

	@Override
	public boolean isSquareEmpty(Location loc) throws InvalidLocation {
	    PlayerPiece piece;
	    
	    if (loc == null) {
	    	throw new InvalidLocation("The location is null.");
	    }
	    
	    piece = getGame().getGameboard().getPlayerPieceFromLocation(loc);
	    
	    if (piece == null) {
	    	return true;
	    }
	    
		return false;
	}

	@Override
	public PlayerPiece getPiece(Location loc) throws PieceNotFound {
	    PlayerPiece piece;
	    piece = getGame().getGameboard().getPlayerPieceFromLocation(loc);
	    if (piece == null) {
	    	throw new PieceNotFound("The piece is not found (aka null).");
	    }

	    return piece;
	}

	@Override
	public long getGameID() {
		GameID gameNum;
		
		gameNum = getGame().getGameID();
		if (gameNum == null) {
			System.out.println("GameID is null and should not be.");
			return 0;
		}
		
		return gameNum.getGameIDLong();
	}


	@Override
	public String getMyName() {
		return ClientLogic.getInstance().getGame().getMyName();
	}


	@Override
	public String getOpponentName() {
		return ClientLogic.getInstance().getGame().getOpponentName();
	}


	@Override
	public TeamColor getMyColor() {
		return ClientLogic.getInstance().getGame().getMyColor();
	}


	@Override
	public TeamColor getOpponentColor() {
		return ClientLogic.getInstance().getGame().getOpponentColor();
	}


	@Override
	public boolean isJoinable() {
		return (ClientLogic.getInstance().getGame().getOpponentName() == null);
	}


	@Override
	public boolean isObservable() {
		return (ClientLogic.getInstance().getGame().getOpponentName() != null);
	}


	@Override
	public void removePiece(Location loc) throws IllegalMove, InvalidLocation, ServerUnreachable {
		PlayerPiece currentPieceInLoc;
		ActionRemove movePiece;
		GameEventNotify gameHandle = ClientLogic.getInstance().getGameEventHandle();
		if (gameHandle == null) {
			System.out.println("ERROR: GameEventNotify handle is null...this should not happen - Debug this");
			return;
		}
		
		/* Ensure the piece we are trying to move is our piece */
		currentPieceInLoc = getGame().getGameboard().getPlayerPieceFromLocation(loc);
		if (currentPieceInLoc == null) {
			throw new IllegalMove("No piece to remove in this location.");
		} else if (currentPieceInLoc.getColor() != getMyColor()) {
			throw new IllegalMove("Trying to remove an opponents piece.");
		}
		
		movePiece = new ActionRemove("Remove Piece", getGame().getGameboard(), currentPieceInLoc, getGame().getGameboard().getBoneyard());
		try {
			movePiece.strategoRulesCheck();
		} catch (ActionNotLegalException e){
			throw new IllegalMove("Remove is not legal.");
		}
		try {
			/* This may need to change if remove piece message is added */
			ClientDownstreamLogic.getInstance().sendDownstream(new MsgMovePiece(getGame().getGameID(), movePiece));
		} catch (Exception e) {
			throw new ServerUnreachable("Could not connect to Server.");
		}
	}

	@Override
	public boolean obfuscatePieces() {
		return getGame().obfuscatePieces();
	}
	
	@Override
	public boolean gameIsObserver() {
		return getGame().isObserverGame();
	}


}
